package com.evil.common.application.dto.order.data;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.annotation.JSONField;
import com.evil.common.core.util.NumberUtils;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.data.annotation.Id;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 控件值 实体
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Data
@Accessors(chain = true)
public class ControlDataDTO {

    @JSONField(serialize = false)
    private Long applicationFormId;

    /**
     * 数据id
     */
    @Id
    private Long orderDataId;

    /**
     * 控件id
     */
    @NotNull(message = "控件id不能为空")
    private Long controlId;

    /**
     * 控件code
     */
    @NotBlank(message = "控件code不能为空")
    private String controlCode;

    /**
     * 控件标题
     */
    private String controlTitle;

    /**
     * 控件序号
     */
    private Integer sort;

    /**
     * 上级控件id
     */
    private Long parentControlId;

    /**
     * 表格数据
     */
    private List<List<ControlDataDTO>> tableValues;

    /**
     * 控件值
     */
    private List<ControlDataValueDTO> values;

    public ControlDataDTO() {
        this.sort = 0;
        this.tableValues = new ArrayList<>();
        this.values = new ArrayList<>();
    }

    public Integer defaultSort() {
        this.sort = NumberUtils.null2Zero(this.sort);
        return sort;
    }

    public ControlDataDTO copy() {
        return this.copy(false);
    }

    /**
     * 复制
     *
     * @param retainId 是否保留orderDataId
     * @return ControlDataDTO
     */
    public ControlDataDTO copy(boolean retainId) {
        ControlDataDTO copy = BeanUtil.copyProperties(this, ControlDataDTO.class);
        if (!retainId) {
            copy.setOrderDataId(null);
        }
        this.copyValue(copy);
        return copy;
    }

    public void copyValue(ControlDataDTO copy) {
        copy.setTableValues(tableValues.stream()
                .map(list -> list.stream().map(ControlDataDTO::copy).toList())
                .toList());
        copy.setValues(values.stream().map(ControlDataValueDTO::copy).toList());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ControlDataDTO that = (ControlDataDTO) o;
        return Objects.equals(applicationFormId, that.applicationFormId)
                && Objects.equals(orderDataId, that.orderDataId)
                && Objects.equals(controlId, that.controlId)
                && Objects.equals(controlCode, that.controlCode)
                && Objects.equals(controlTitle, that.controlTitle)
                && Objects.equals(sort, that.sort)
                && Objects.equals(parentControlId, that.parentControlId)
                && this.equalsTableValues(that.tableValues)
                && this.equalsValues(that.values);
    }

    @Override
    public int hashCode() {
        return Objects.hash(applicationFormId, orderDataId, controlId, controlCode, controlTitle, sort, parentControlId, tableValues, values);
    }

    public boolean equalsTableValues(List<List<ControlDataDTO>> tableValues) {
        if (this.tableValues == tableValues) return true;
        if (this.tableValues.size() != tableValues.size()) return false;
        for (int i = 0; i < this.tableValues.size(); i++) {
            List<ControlDataDTO> thisDataList = this.tableValues.get(0);
            List<ControlDataDTO> dataList = tableValues.get(0);
            if (thisDataList.size() != dataList.size()) {
                return false;
            }
            for (int ii = 0; ii < thisDataList.size(); ii++) {
                ControlDataDTO thisData = thisDataList.get(ii);
                ControlDataDTO data = dataList.get(ii);
                if (!thisData.equals(data)) {
                    return false;
                }
            }
        }
        return true;
    }

    public boolean equalsValues(List<ControlDataValueDTO> values) {
        if (this.values == values) return true;
        if (this.values.size() != values.size()) return false;
        for (int i = 0; i < this.values.size(); i++) {
            ControlDataValueDTO thisValue = this.values.get(i);
            ControlDataValueDTO value = values.get(i);
            if (!thisValue.equals(value)) {
                return false;
            }
        }
        return false;
    }
}
